package com.ljb.utilslibrary.ossutils;

import android.content.Context;
import android.util.Log;

import com.alibaba.sdk.android.oss.ClientException;
import com.alibaba.sdk.android.oss.OSS;
import com.alibaba.sdk.android.oss.OSSClient;
import com.alibaba.sdk.android.oss.ServiceException;
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback;
import com.alibaba.sdk.android.oss.callback.OSSProgressCallback;
import com.alibaba.sdk.android.oss.common.auth.OSSCredentialProvider;
import com.alibaba.sdk.android.oss.common.auth.OSSPlainTextAKSKCredentialProvider;
import com.alibaba.sdk.android.oss.common.utils.BinaryUtil;
import com.alibaba.sdk.android.oss.internal.OSSAsyncTask;
import com.alibaba.sdk.android.oss.model.DeleteObjectRequest;
import com.alibaba.sdk.android.oss.model.DeleteObjectResult;
import com.alibaba.sdk.android.oss.model.GetObjectRequest;
import com.alibaba.sdk.android.oss.model.GetObjectResult;
import com.alibaba.sdk.android.oss.model.ObjectMetadata;
import com.alibaba.sdk.android.oss.model.PutObjectRequest;
import com.alibaba.sdk.android.oss.model.PutObjectResult;
import com.google.gson.Gson;
import com.ljb.utilslibrary.ossutils.listener.DeleteCBListener;
import com.ljb.utilslibrary.ossutils.listener.DownLoadCBListener;
import com.ljb.utilslibrary.ossutils.listener.UploadCBListener;

import java.io.IOException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * OSS对象存储功能的工具类
 * Created by lijianbin on 2016/11/21.
 */
public class OssController {
    private static final String TAG = "OssController";
    //Oss配置参数
    private static String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
    private static String accessKeyId = "LTAIeulhTcVibhf0";
    private static String accessKeySecret = "CoLhdTp6RLJqbI4WINE36OoaC1whsz";

    //    private static String endpoint;
//    private static String accessKeyId;
//    private static String accessKeySecret;
    //bucket名称
    public static String BUCKET_APP = "jk-cloud-app";
    public static String BUCKET_MONITOR_XML = "jk-cloud-monitor-xml";
    //操作对象
    private volatile static OssController ossController;
    //OSS客户端
    private volatile OSS oss;
    //自定义metadata
    private ObjectMetadata metadata;


    /**
     * 初始化Oss需要的参数
     */
    public static void iniOssInfo() {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url("http://app.shukuang.cn/ZHSW_APP_INTERFACE/sys/config/list-data.ajax").build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.e(TAG, "onFailure: OSS获取参数失败");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Log.e(TAG, "onResponse: OSS获取参数成功");
                String result = response.body().string();
                OssInfoModel ossInfoModel = new Gson().fromJson(result, OssInfoModel.class);
                endpoint = ossInfoModel.data.url;
                accessKeyId = ossInfoModel.data.accessKeyId;
                accessKeySecret = ossInfoModel.data.accessKeySecret;
                Log.e(TAG, "onResponse: \nendpoint: " + endpoint + ",\naccessKeyId: " + accessKeyId + ",\naccessKeySecret: " + accessKeySecret);
            }
        });
    }

    /**
     * 获取单例的Oss操作对象
     *
     * @return 单例对象
     */
    public static OssController getInstance(Context context) {
        if (ossController == null) {
            synchronized (OssController.class) {
                if (ossController == null) {
                    ossController = new OssController(context);
                }
            }
        }
        return ossController;
    }

    /**
     * 私有构造方法,初始化Oss客户端
     */
    private OssController(Context context) {
        if (accessKeyId != null && accessKeySecret != null && !accessKeyId.isEmpty() && !accessKeySecret.isEmpty()) {
            OSSCredentialProvider credentialProvider = new OSSPlainTextAKSKCredentialProvider(accessKeyId, accessKeySecret);
            oss = new OSSClient(context, endpoint, credentialProvider);
        }
    }

/****************************************************************************************************/

    /**
     * 上传文件时,设置文本类型,如不设置的话,会根据文件后缀自动添加
     *
     * @param contentType 文件类型
     * @param meta_name   metadata名称
     * @param value       metadata值
     */
    public void setContentType(String contentType, String meta_name, String value) {
        metadata = new ObjectMetadata();
        // 指定Content-Type
        metadata.setContentType(contentType);
        // user自定义metadata
        metadata.addUserMetadata(meta_name, value);
    }

    /**
     * Oss下载文件到本地(异步接口,直接在UI线程调用)
     *
     * @param objectKey 文件名称
     * @param listener  回调监听
     * @return task异步任务, 可以调用task.cancel()取消任务, task.waitUntilFinished()等待直到任务完成
     */
    public OSSAsyncTask downloadObject(String bucket, String objectKey, DownLoadCBListener listener) {
        return getObject(bucket, objectKey, listener);
    }

    /**
     * 本地文件上传到OSS(异步接口,直接在UI线程调用)
     *
     * @param objectKey      文件名称,如果想在OSS中显示层级结构,可以把objectKey写为"folder/subfolder/file"的格式,注意不能以'/'开头
     * @param uploadFilePath 文件上传路径
     * @param listener       回调监听
     * @return task异步任务, 可以调用task.cancel()取消任务, task.waitUntilFinished()等待直到任务完成
     */
    public OSSAsyncTask uploadObject(String bucket, String objectKey, String uploadFilePath, UploadCBListener listener) {
        return putObject(bucket, objectKey, uploadFilePath, listener);
    }

    /**
     * 判断 OSS的bucket中的文件是否存在
     *
     * @param objectKey 文件名称
     * @return true表示存在, false表示不存在或其他原因造成验证失败, 具体看日志
     */
    public boolean isExist(String bucket, String objectKey) {
        try {
            if (oss.doesObjectExist(bucket, objectKey)) {
                Log.d("doesObjectExist", "object exist.");
                return true;
            } else {
                Log.d("doesObjectExist", "object does not exist.");
                return false;
            }
        } catch (ClientException e) {
            // 本地异常如网络异常等
            e.printStackTrace();
            return false;
        } catch (ServiceException e) {
            // 服务异常
            Log.e("ErrorCode", e.getErrorCode());
            Log.e("RequestId", e.getRequestId());
            Log.e("HostId", e.getHostId());
            Log.e("RawMessage", e.getRawMessage());
            return false;
        }
    }

    /**
     * 删除OSS buket中的文件
     *
     * @param objectKey 文件名称
     * @param listener  回调监听,如只需要知道是否删除成功,可以传null
     * @return task异步任务, 可以调用task.cancel()取消任务, task.waitUntilFinished()等待直到任务完成
     */

    public OSSAsyncTask deleteObject(String bucket, String objectKey, final DeleteCBListener listener) {
        // 创建删除请求
        DeleteObjectRequest delete = new DeleteObjectRequest(bucket, objectKey);
        // 异步删除
        OSSAsyncTask deleteTask = oss.asyncDeleteObject(delete, new OSSCompletedCallback<DeleteObjectRequest, DeleteObjectResult>() {
            @Override
            public void onSuccess(DeleteObjectRequest request, DeleteObjectResult result) {
                Log.d("asyncCopyAndDelObject", "success!");
                if (listener != null) {
                    listener.onSuccess(request, result);
                }
            }

            @Override
            public void onFailure(DeleteObjectRequest request, ClientException clientExcepion, ServiceException serviceException) {
                // 请求异常
                if (clientExcepion != null) {
                    // 本地异常如网络异常等
                    clientExcepion.printStackTrace();
                }
                if (serviceException != null) {
                    // 服务异常
                    Log.e("ErrorCode", serviceException.getErrorCode());
                    Log.e("RequestId", serviceException.getRequestId());
                    Log.e("HostId", serviceException.getHostId());
                    Log.e("RawMessage", serviceException.getRawMessage());
                }
                if (listener != null) {
                    listener.onSuccess(request, clientExcepion, serviceException);
                }
            }
        });

        return deleteTask;
    }

    /***********************************************************************************************/


    /**
     * 下载文件
     *
     * @param objectKey
     * @param listener
     * @return task
     */
    private OSSAsyncTask getObject(String bucket, String objectKey, final DownLoadCBListener listener) {
        GetObjectRequest get = new GetObjectRequest(bucket, objectKey);
        OSSAsyncTask task = oss.asyncGetObject(get, new OSSCompletedCallback<GetObjectRequest, GetObjectResult>() {
            @Override
            public void onSuccess(GetObjectRequest request, GetObjectResult result) {
                // 请求成功
                listener.onSuccess(result.getObjectContent());
            }

            @Override
            public void onFailure(GetObjectRequest request, ClientException clientExcepion, ServiceException serviceException) {
                // 请求异常
                if (clientExcepion != null) {
                    // 本地异常如网络异常等
                    clientExcepion.printStackTrace();
                }
                if (serviceException != null) {
                    // 服务异常
                    Log.e("ErrorCode", serviceException.getErrorCode());
                    Log.e("RequestId", serviceException.getRequestId());
                    Log.e("HostId", serviceException.getHostId());
                    Log.e("RawMessage", serviceException.getRawMessage());
                }
                listener.onFailure(request, clientExcepion, serviceException);
            }
        });

        return task;
    }

    /**
     * 文件上传
     *
     * @param bucket
     * @param objectKey      文件名称
     * @param uploadFilePath 文件路径
     * @return task
     */
    private OSSAsyncTask putObject(String bucket, String objectKey, String uploadFilePath, final UploadCBListener listener) {
        // 构造上传请求
        PutObjectRequest put = new PutObjectRequest(bucket, objectKey, uploadFilePath);

        if (metadata == null) {
            metadata = new ObjectMetadata();
        }
        put.setMetadata(metadata);

//        setContentMD5(metadata, uploadFilePath);

        // 异步上传时可以设置进度回调
        put.setProgressCallback(new OSSProgressCallback<PutObjectRequest>() {
            @Override
            public void onProgress(PutObjectRequest request, long currentSize, long totalSize) {
                Log.d("PutObject", "currentSize: " + currentSize + " totalSize: " + totalSize);
                if (listener != null) {
                    listener.onProgress(request, currentSize, totalSize);
                }
            }
        });

        OSSAsyncTask task = oss.asyncPutObject(put, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
            @Override
            public void onSuccess(PutObjectRequest request, PutObjectResult result) {
                Log.d("PutObject", "UploadSuccess");
                if (listener != null) {
                    listener.onSuccess(request, result);
                }
            }

            @Override
            public void onFailure(PutObjectRequest request, ClientException clientExcepion, ServiceException serviceException) {
                // 请求异常
                if (clientExcepion != null) {
                    // 本地异常如网络异常等
                    clientExcepion.printStackTrace();
                }
                if (serviceException != null) {
                    // 服务异常
                    Log.e("ErrorCode", serviceException.getErrorCode());
                    Log.e("RequestId", serviceException.getRequestId());
                    Log.e("HostId", serviceException.getHostId());
                    Log.e("RawMessage", serviceException.getRawMessage());
                }
                if (listener != null) {
                    listener.onFailure(request, clientExcepion, serviceException);
                }
            }
        });
        return task;
    }


    /**
     * 设置MD5校验上传文件是否一致
     *
     * @param metadata
     * @param uploadFilePath
     */
    private void setContentMD5(ObjectMetadata metadata, String uploadFilePath) {
        try {
            // 设置Md5以便校验
            metadata.setContentMD5(BinaryUtil.calculateBase64Md5(uploadFilePath)); // 如果是从文件上传
            // metadata.setContentMD5(BinaryUtil.calculateBase64Md5(byte[])); // 如果是上传二进制数据
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
